package com.xinan.system.generat;

import com.jfinal.kit.PathKit;
import com.jfinal.kit.StringKit;
import com.jfinal.plugin.activerecord.TableMapping;
import com.xinan.system.curd.CurdController;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;

/**
 * Created by ERICLEE on 13-6-3.
 */
public class GeneratController extends CurdController {
    private Logger log = LoggerFactory.getLogger(getClass());

    /**
     * 页面跳转
     */
    public void index() {
        render("/WEB-INF/views/generat/generat.html");
    }

    /**
     * 通过数据库连接获取到所有的表
     */
    public void tables(){
        TableFactory tbFactory = TableFactory.getInstance();
        List<Table> t = tbFactory.getAllTables();
        renderJson(t);
    }

    /**
     * 根据选择的表和配置的子目录，生成java文件和html页面
     * @throws IOException
     */
    public void create() throws IOException {
        String tbNames = getPara("tables");
        String basePackage = getPara("basepackage");
        String subPackage = getPara("subpackage");
        if(StringKit.isBlank(tbNames) || StringKit.isBlank(basePackage) || StringKit.isBlank(subPackage)){
            renderJson("表名和包名不能为空！");
            return;
        }
        log.info("所选择的的表：" + tbNames);
        try {
            TableFactory tbFactory = TableFactory.getInstance();
            //如果是多个表同时生成，则可以根据提交的表名，循环生成
            String[] tbs = tbNames.split(",");
            for(String tbName : tbs){
                Table t = tbFactory.getTable(tbName);
                if(t!=null){
                    File templateRootDir = new File(PathKit.getWebRootPath()+"/template");
                    List<File> srcFiles = searchAllNotIgnoreFile(templateRootDir);
                    Map templateModel = new HashMap();
                    templateModel.put("table", t);
                    templateModel.put("className",t.getClassName());
                    templateModel.put("classNameLower",t.getClassNameLower());
                    templateModel.put("basepackage",basePackage);
                    templateModel.put("subpackage",subPackage);
                    Configuration conf = new Configuration();
                    conf.setDirectoryForTemplateLoading(templateRootDir);
                    for(int i = 0; i < srcFiles.size(); i++){
                        File srcFile = srcFiles.get(i);
                        if(srcFile.isDirectory() || srcFile.getName().toLowerCase().endsWith(".include")){
                            continue;
                        }
                        executeGenerate(templateRootDir, templateModel, srcFile, conf);
                    }
                    renderJson("表对象生成成功！");
                }else{
                    renderJson("表对象不存在！");
                }
            }
        }catch(Exception e) {
            log.error("生成模板时出现异常：" + e.getMessage());
            renderJson("表对象生成失败！");
        }
    }

    private void executeGenerate(File templateRootDir, Map templateModel, File srcFile, Configuration conf) throws IOException,TemplateException {
        String templateFile = getRelativePath(templateRootDir, srcFile);
        String outputFilepath = processTemplateString(templateFile, templateModel, conf);

        if(StringKit.notBlank(outputFilepath)) {
            Template template = conf.getTemplate(templateFile);
            String filePath = PathKit.getWebRootPath()+"/WEB-INF/views/"+templateModel.get("subpackage")+"/"+outputFilepath;
            if(outputFilepath.endsWith(".java")){
                filePath = PathKit.getWebRootPath()+"/../src/"+templateModel.get("basepackage").toString().replaceAll("\\.", "/") + "/" +templateModel.get("subpackage")+"/"+outputFilepath;
            }
            File absoluteOutputFilePath = parentMkdir(filePath);
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(absoluteOutputFilePath),"UTF-8"));
            template.process(templateModel,out);
            out.close();
        }
    }

    /**
     * 得到相对路径
     */
    public static String getRelativePath(File baseDir,File file) {
        if(baseDir.equals(file))
            return "";
        if(baseDir.getParentFile() == null)
            return file.getAbsolutePath().substring(baseDir.getAbsolutePath().length());
        return file.getAbsolutePath().substring(baseDir.getAbsolutePath().length()+1);
    }

    public static String processTemplateString(String templateString,Map model,Configuration conf) throws IOException, TemplateException {
        StringWriter out = new StringWriter();
        Template template = new Template("templateString...",new StringReader(templateString),conf);
        template.process(model, out);
        return out.toString();
    }

    private List<File> searchAllNotIgnoreFile(File dir) throws IOException {
        ArrayList arrayList = new ArrayList();
        searchAllNotIgnoreFile(dir,arrayList);
        Collections.sort(arrayList, new Comparator<File>() {
            public int compare(File o1, File o2) {
                return o1.getAbsolutePath().compareTo(o2.getAbsolutePath());
            }
        });
        return arrayList;
    }

    private void searchAllNotIgnoreFile(File dir,List<File> collector) throws IOException {
        collector.add(dir);
        if((!dir.isHidden() && dir.isDirectory())) {
            File[] subFiles = dir.listFiles();
            for(int i = 0; i < subFiles.length; i++) {
                searchAllNotIgnoreFile(subFiles[i],collector);
            }
        }
    }

    public static File parentMkdir(String file) {
        if(file == null) throw new IllegalArgumentException("file must be not null");
        File result = new File(file);
        parnetMkdir(result);
        return result;
    }

    public static void parnetMkdir(File outputFile) {
        if(outputFile.getParentFile() != null) {
            outputFile.getParentFile().mkdirs();
        }
    }
}
